﻿//---------------------------------------------------------------------------
// <copyright file="RibbonApplicationMenuItem.cs" company="Microsoft Corporation">
//     Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//---------------------------------------------------------------------------

namespace Microsoft.Windows.Controls.Ribbon
{
    #region Using declarations

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    using System.Windows.Data;
    using System.Windows.Media;

    #endregion

    /// <summary>
    ///   Implements a MenuItem in the Ribbon's ApplicationMenu.
    /// </summary>
    public class RibbonApplicationMenuItem : MenuItem
    {
        #region Fields

        /// <summary>
        ///   The RibbonApplicationMenuItem's Popup.
        /// </summary>
        private Popup _popup;

        #endregion

        #region Constructors

        /// <summary>
        ///   Initializes static members of the RibbonApplicationMenuItem class.  This also
        ///   overrides the default style, the Command PropertyChangedCallback, and the default
        ///   RibbonControlSizeDefintion for a MenuItem.
        /// </summary>
        static RibbonApplicationMenuItem()
        {
            Type ownerType = typeof(RibbonApplicationMenuItem);

            DefaultStyleKeyProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(ownerType));
            CommandProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnCommandChanged)));
            ToolTipProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(null, new CoerceValueCallback(CoerceToolTip)));
            ToolTipService.ShowOnDisabledProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(true));

            FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(
                new RibbonControlSizeDefinition() { ImageSize = RibbonImageSize.Small, IsLabelVisible = false },
                null,
                new CoerceValueCallback(OnCoerceControlSizeDefinition));

            RibbonGroup.ControlSizeDefinitionProperty.OverrideMetadata(ownerType, metadata);           
        }

        #endregion

        #region Private Properties

        /// <summary>
        ///   Gets the parent ItemsControl for this MenuItem.
        /// </summary>
        private ItemsControl ParentItemsControl
        {
            get { return ItemsControl.ItemsControlFromItemContainer(this); }
        }

        #endregion

        #region Public Methods

        /// <summary>
        ///   If the developer hasn't assigned their own tooltip, Create and attach a new RibbonToolTip.
        /// </summary>
        /// <param name="d">
        ///   The RibbonApplicationMenuItem that the ToolTip property exists on.  When the callback is invoked,
        ///   the property system will pass this value.
        /// </param>
        /// <param name="value">The new value of the ToolTip property, prior to any coercion attempt.</param>
        /// <returns>The coerced value of the ToolTip property.</returns>
        public static object CoerceToolTip(DependencyObject d, object value)
        {
            RibbonApplicationMenuItem rami = (RibbonApplicationMenuItem)d;

            if (value == null)
            {
                RibbonCommand command = rami.Command as RibbonCommand;
                if (command != null &&
                    (!string.IsNullOrEmpty(command.ToolTipTitle) || !string.IsNullOrEmpty(command.ToolTipDescription) || command.ToolTipImageSource != null))
                {
                    RibbonToolTip tt = new RibbonToolTip(command);
                    tt.Placement = PlacementMode.Mouse;
                    value = tt;
                }
            }

            return value;
        }

        /// <summary>
        ///   Invoked whenever the control's template is applied.
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            // Cleanup the previous template elements
            if (_popup != null)
            {
                _popup.Opened -= new EventHandler(this.OnPopupOpened);
            }

            // First level items
            if (this.ParentItemsControl is RibbonApplicationMenu)
            {
                _popup = this.GetTemplateChild("PART_Popup") as Popup;

                if (_popup != null)
                {
                    _popup.Opened += new EventHandler(this.OnPopupOpened);
                }
            }
        }

        #endregion

        #region Protected Methods

        /// <summary>
        ///   Called when the MenuItem is initialized.  This updates the ControlSizeDefinition.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected override void OnInitialized(EventArgs e)
        {
            // This will update the menu item role
            base.OnInitialized(e);

            CoerceValue(RibbonGroup.ControlSizeDefinitionProperty);
        }

        #endregion

        #region Private Methods

        /// <summary>
        ///   Coerces the value of the ControlSizeDefinition for this MenuItem.  This value
        ///   will be set differently depending on how deeply nested the MenuItem is within
        ///   the Menu tree.
        /// </summary>
        /// <param name="o">
        ///   The MenuItem whose ControlSizeDefinition is being coerced.  When
        ///   the callback is invoked, the property system will pass this value.
        /// </param>
        /// <param name="value">The new value of the ControlSizeDefinition property, prior to any coercion attempt.</param>
        /// <returns>The coerced value of the ControlSizeDefinition property.</returns>
        private static object OnCoerceControlSizeDefinition(DependencyObject o, object value)
        {
            RibbonApplicationMenuItem menuItem = o as RibbonApplicationMenuItem;

            if (menuItem != null)
            {
                ItemsControl menuItemParent = menuItem.ParentItemsControl;

                // First level items
                if (menuItemParent is RibbonApplicationMenu)
                {
                    return new RibbonControlSizeDefinition() { ImageSize = RibbonImageSize.Small, IsLabelVisible = true };
                }

                ItemsControl menuItemParentParent = ItemsControl.ItemsControlFromItemContainer(menuItemParent);

                // Second level items
                if (menuItemParentParent is RibbonApplicationMenu)
                {
                    return new RibbonControlSizeDefinition() { ImageSize = RibbonImageSize.Large, IsLabelVisible = true };
                }
            }

            return value;
        }

        /// <summary>
        ///   If the Command property changes, we need to coerce some RibbonControl
        ///   specific properties to update their 'back-up' values coming from Command.
        /// </summary>
        /// <param name="d">The RibbonApplicationMenu on which the Command property has changed value.</param>
        /// <param name="e">
        ///   Event data that is issued by any event that tracks changes to the effective value of this property.
        /// </param>
        private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            d.CoerceValue(ToolTipProperty);
            d.CoerceValue(HeaderProperty);
            d.CoerceValue(IconProperty);
        }

        /// <summary>
        ///   Called when the RibbonApplicationMenu's popup is opened.
        /// </summary>
        /// <param name="sender">The RibbonApplicationMenu whose popup is opening.</param>
        /// <param name="e">The event data.</param>
        private void OnPopupOpened(object sender, EventArgs e)
        {
            RibbonApplicationMenu ram = ItemsControl.ItemsControlFromItemContainer(this) as RibbonApplicationMenu;
            if (ram != null)
            {
                Rect relativeRect = ram.GetRelativeSubmenuRect(this);
                if (relativeRect.Height > 0 && relativeRect.Width > 0)
                {
                    _popup.Placement = PlacementMode.Relative;
                    _popup.HorizontalOffset = relativeRect.X;
                    _popup.VerticalOffset = relativeRect.Y;
                    _popup.Width = relativeRect.Width;
                    _popup.Height = relativeRect.Height;
                }
            }
        }

        #endregion
    }
}